<i18n locale="zh-CN" lang="yaml">
Jump to...    : 跳转到...
Refresh       : 刷新列表
New ENV       : 新建环境变量
Setup         : 配置
Usage         : 用法
Example       : 示例
Copy {name} ID: 复制{name} ID

ENV Variable pinned  : 环境变量已置顶
ENV Variable unpinned: 环境变量已取消
ENV Variable deleted : 环境变量已删除

Are you sure you want to delete the ENV?<br><strong class="text-bad">{label}</strong>: 是否确认删除此环境变量？<br><strong class="text-bad">{label}</strong>
</i18n>

<!-- Generated by OpenCC START -->
<i18n locale="zh-HK" lang="yaml">
Are you sure you want to delete the ENV?<br><strong class="text-bad">{label}</strong>: 是否確認刪除此環境變量？<br><strong class="text-bad">{label}</strong>
Copy {name} ID: 複製{name} ID
ENV Variable deleted: 環境變量已刪除
ENV Variable pinned: 環境變量已置頂
ENV Variable unpinned: 環境變量已取消
Example: 示例
Jump to...: 跳轉到...
New ENV: 新建環境變量
Refresh: 刷新列表
Setup: 配置
Usage: 用法
</i18n>
<i18n locale="zh-TW" lang="yaml">
Are you sure you want to delete the ENV?<br><strong class="text-bad">{label}</strong>: 是否確認刪除此環境變數？<br><strong class="text-bad">{label}</strong>
Copy {name} ID: 複製{name} ID
ENV Variable deleted: 環境變數已刪除
ENV Variable pinned: 環境變數已置頂
ENV Variable unpinned: 環境變數已取消
Example: 示例
Jump to...: 跳轉到...
New ENV: 新建環境變數
Refresh: 重新整理列表
Setup: 配置
Usage: 用法
</i18n>
<!-- Generated by OpenCC END -->

<template>
  <div id="aside-env-variable-content" class="aside-inner-content">
    <div class="jump-to-select-wrap">
      <el-select class="jump-to-select"
        :placeholder="$t('Jump to...')"
        :no-data-text="$t('No Data')"
        size="small"
        clearable
        filterable
        :filter-method="T.debounce(doFilter)"
        v-model="selectFilterText">
        <el-option
          v-for="item in selectShowOptions"
          :key="item.id"
          :label="item.label"
          :value="item.id">
          <span class="select-item-name">
            <el-tag class="aside-tree-node-tag"
              :type="C.ENV_VARIABLE_MAP.get(item.autoTypeCasting).tagType"
              size="mini">{{ C.ENV_VARIABLE_MAP.get(item.autoTypeCasting).name }}</el-tag>
            {{ item.label }}
          </span>
          <code class="select-item-id code-font">ID: {{ item.id }}</code>
        </el-option>
      </el-select>
    </div>

    <el-tree class="aside-tree"
      v-loading="loading"
      :data="data"
      :highlight-current="true"
      :indent="10"
      node-key="id"
      ref="tree">

      <span
        slot-scope="{node, data}"
        class="aside-tree-node"
        :entry-id="data.id"
        @click="openEntity(data)">

        <!-- Menu -->
        <el-popover
          placement="right-start"
          trigger="hover"
          popper-class="aside-tip"
          :disabled="!!!data.id"
          v-model="data.showPopover">

          <div slot="reference" class="aside-item">
            <!-- Items -->
            <span>
              <el-link v-if="data.type === 'refresh'" type="primary">
                <i class="fa fa-fw fa-refresh"></i> {{ $t('Refresh') }}
              </el-link>
              <el-link v-else-if="data.type === 'addEnvVariable'" type="primary">
                <i class="fa fa-fw fa-plus"></i> {{ $t('New ENV') }}
              </el-link>
              <div v-else>
                <el-tag class="aside-tree-node-tag"
                  :type="C.ENV_VARIABLE_MAP.get(data.autoTypeCasting).tagType"
                  size="mini">{{ C.ENV_VARIABLE_MAP.get(data.autoTypeCasting).name }}</el-tag>
                <span :class="{'text-strong': data.isPinned}">{{ node.label }}</span>
              </div>
            </span>

            <!-- Status icon -->
            <div>
              <el-tooltip effect="dark" :content="$t('Pinned')" placement="top" :enterable="false">
                <i class="fa fa-fw text-bad" :class="[ data.isPinned ? 'fa-thumb-tack':'' ]"></i>
              </el-tooltip>
            </div>
          </div>

          <!-- Basic info -->
          <div class="aside-tree-node-description">
            <div>
              <el-tag class="aside-tree-node-tag-title"
                :type="C.ENV_VARIABLE_MAP.get(data.autoTypeCasting).tagType"
                size="mini">{{ C.ENV_VARIABLE_MAP.get(data.autoTypeCasting).name }}</el-tag>
            </div>

            <span class="text-info">ID</span>
            &nbsp;<code class="text-main">{{ data.id }}</code>
            <CopyButton :content="data.id" />

            <pre v-if="data.description">{{ data.description }}</pre>
          </div>

          <!-- Sample code -->
          <template v-if="data.sampleUsage">
            <div class="aside-tree-node-sample">
              <span class="text-info">{{ $t('Usage') }}</span>
              <CopyButton :content="data.sampleUsage" />

              <pre>{{ data.sampleUsage }}</pre>
            </div>
          </template>
          <template v-if="data.sampleCode">
            <div class="aside-tree-node-sample">
              <span class="text-info">{{ $t('Example') }}</span>
              <CopyButton :content="data.sampleCode" />

              <pre>{{ data.sampleCode }}</pre>
            </div>
          </template>

          <!-- Operation -->
          <br>
          <div class="controls-bar">
            <el-button-group>
              <!-- Setup / View -->
              <el-button
                size="small"
                @click="openEntity(data, 'setup')">
                <i class="fa fa-fw fa-wrench"></i>
                {{ $t('Setup') }}
              </el-button>

              <!-- Pin -->
              <el-button
                size="small"
                :class="data.isPinned ? 'button-group-actived' : ''"
                @click="pinData(data.type, data.id, !data.isPinned)">
                <i class="fa fa-fw" :class="[data.isPinned ? 'fa-thumb-tack fa-rotate-270' : 'fa-thumb-tack']"></i>
                {{ data.isPinned ? $t('Unpin') : $t('Pin') }}
              </el-button>
            </el-button-group>
          </div>
        </el-popover>
      </span>
    </el-tree>

    <EnvVariableSetup ref="setup" />
  </div>
</template>

<script>
import EnvVariableSetup from '@/components/Development/EnvVariableSetup'

export default {
  name: 'AsideEnvVariable',
  components: {
    EnvVariableSetup,
  },
  watch: {
    selectFilterText(val) {
      if (!val) return;
      if (!this.$refs.tree) return;

      let node = this.$refs.tree.getNode(val);
      this.openEntity(node.data, null, { scroll: true });
    },
    '$store.state.envVariableListSyncTime': function() {
      this.loadData();
    },
  },
  methods: {
    doFilter(q) {
      q = (q || '').toLowerCase().trim();
      if (!q) {
        this.selectShowOptions = this.selectOptions;
      } else {
        this.selectShowOptions = this.common.filterByKeywords(q, this.selectOptions);
      }
    },

    selectNode(nodeKey, options) {
      options = options || {};

      if (!this.$refs.tree) return;
      if (!nodeKey) return;

      setImmediate(() => {
        let node = this.$refs.tree.getNode(nodeKey);
        if (!node || !node.data) return;

        this.$refs.tree.setCurrentKey(node.data.id);

        // Scroll to element
        this.common.scrollAside('aside-env-variable-content', node.data.id);
      });
    },

    async loadData() {
      this.loading = true;

      let apiRes = await this.T.callAPI_getAll('/api/v1/env-variables/do/list', {
        query: {
          fields: [
            'id',
            'title',
            'description',
            'autoTypeCasting',
            'isPinned',
            'pinTime',
          ]
        },
      });
      if (!apiRes || !apiRes.ok) return;

      let treeData = [];
      window._DFF_envVariableIds = [];
      apiRes.data.forEach(d => {
        window._DFF_envVariableIds.push(d.id);

        // Reduce the number of description lines
        d.description = this.T.limitLines(d.description);

        // Sample code
        let sampleUsage = `DFF.ENV('${d.id}')`;
        let sampleCode  = `${d.id} = DFF.ENV('${d.id}')`;

        // Create node data
        let treeNode = {
          id        : d.id,
          label     : d.title || d.id,
          type      : 'envVariable',
          isPinned  : d.isPinned,
          pinTime   : d.pinTime,

          title          : d.title,
          description    : d.description,
          autoTypeCasting: d.autoTypeCasting,

          sampleUsage: sampleUsage,
          sampleCode : sampleCode,

          showPopover: false,
        };
        this.common.appendSearchFields(treeNode, ['id', 'title'])

        treeData.push(treeNode);
      });
      treeData.sort(this.common.asideItemSorter);
      treeData.unshift({type: 'addEnvVariable'});
      treeData.unshift({type: 'refresh'});

      // Generate selector options
      let selectOptions = treeData.filter(x => x.type === 'envVariable');

      this.loading           = false;
      this.data              = treeData;
      this.selectOptions     = selectOptions;
      this.selectShowOptions = selectOptions;

      // Select automatically
      this.selectNode(this.$route.params.id, { scroll: true });
    },
    async pinData(dataType, dataId, isPinned) {
      let apiPath   = null;
      let okMessage = null;
      switch(dataType) {
        case 'envVariable':
          apiPath   = '/api/v1/env-variables/:id/do/modify';
          okMessage = isPinned
                    ? this.$t('ENV Variable pinned')
                    : this.$t('ENV Variable unpinned');
          break;

        default:
          return;
      }
      let apiRes = await this.T.callAPI('post', apiPath, {
        params  : { id: dataId },
        body    : { data: { isPinned: isPinned } },
        feedback: { okMessage: okMessage },
      });
      if (!apiRes || !apiRes.ok) return;

      this.$store.commit('updateEnvVariableListSyncTime');
    },
    openEntity(data, target, options) {
      options = options || {};

      data.showPopover = false;

      switch(data.type) {
        case 'refresh':
          this.loadData();
          break;

        case 'addEnvVariable':
          this.$refs.setup.loadData();
          break;

        case 'envVariable':
          this.selectNode(data.id, options);
          this.$refs.setup.loadData(data.id);
          break;

        default:
          console.error(`Unexcepted data type: ${data.type}`);
          break;
      }
    },
    async deleteEntity(data) {
      if (!await this.T.confirm(this.$t('Are you sure you want to delete the ENV?<br><strong class="text-bad">{label}</strong>', { label: data.label }))) return;

      let apiRes = await this.T.callAPI('/api/v1/env-variables/:id/do/delete', {
        params  : { id: data.id },
        feedback: { okMessage: this.$t('ENV Variable deleted') },
      });
      if (!apiRes || !apiRes.ok) return;

      this.$store.commit('updateEnvVariableListSyncTime');
    },
  },
  props: {
  },
  data() {
    return {
      loading: false,
      data   : [],

      selectFilterText : '',
      selectOptions    : [],
      selectShowOptions: [],
    };
  },
  created() {
    this.loadData();
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.jump-to-select {
  position: absolute;
  left: 5px;
  right: 5px;
  z-index: 9;
}
.select-item-name {
  float: left;
}
.select-item-id {
  float: right;
  padding-left: 30px;
  font-size: 12px;
}

.aside-tree {
  padding-top: 35px;
  padding-bottom: 10px;
}
.aside-tree-node-tag {
  width: 90px;
  text-align: center;
}
.aside-tree-node-tag-title {
  width: 100%;
  text-align: center;
  margin-bottom: 10px;
}
.aside-tree-node-tag * {
  font-family: Arial;
}
.aside-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
  padding-right: 8px;
  height: 31px;
  max-width: 100%;
  overflow: hidden;
}
.aside-tree-node i.fa {
  font-size: 14px;
}
.aside-tip pre {
  padding: 0 0 0 10px;
  margin: 0;
  font-size: 14px;
}
.aside-tree-node-description {

}
.aside-tree-node-sample {
  padding-top: 10px;
  text-align: left;
}

.aside-tree-node > span {
  display: block;
  width: 100%;
}
.aside-item {
  height: 31px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
</style>
